import { EventEmitter } from "events";
import { Socket } from "net";
import { join } from "path";
import { Server } from "ws";
import { IGlobal } from "../../../entity/Global";
import { ClsUtils, FileUtils } from "../../../Index";
import { HttpUtils } from "../../../utils/HttpUtils";
import { IProtocol } from "../protocol/IProtocol";
import { IProtocolData } from "../protocol/IProtocolData";
import { JsonProtocol } from "../protocol/JsonProtocol";
import { SocketClient } from "./SocketClient";
import { WsBaseService } from "./WsBaseService";
var crypto = require('crypto');

function createkey() {
    var md5 = crypto.createHash('md5');
    var d = { time: Date.now(), key: Math.random() };
    return md5.update(JSON.stringify(d)).digest('hex');
}
declare var global: IGlobal;
/**
 * socket服务监听，客户端连接初始化
 */
export class WsServer extends EventEmitter {
    static NAME = "PlusWsServer";
    static DefaultProtocol: IProtocol = new JsonProtocol();
    private _ws: Server;
    private _clientHash: any;
    private _keyHash: any;
    private _linkCount: number = 0;
    private _port: number;
    private _path: string;
    private _serverHash: { [serverName: string]: typeof WsBaseService };
    private _protocol: IProtocol;
    protected _isProxy: boolean;
    public verifyFunc:(info:object)=>boolean;
    constructor(port: number, path: string, protocol?: IProtocol, isProxy: boolean = false) {
        super();
        this._port = port;
        this._path = path;
        this._isProxy = isProxy;
        this._serverHash = {};
        this._protocol = protocol || WsServer.DefaultProtocol;
    }

    init() {
        this._ws = new Server({
            port: this._port, //监听接口  
            verifyClient: this._socketVerify.bind(this) //可选，验证连接函数  
        });
        this._clientHash = {};
        this._keyHash = {};
        this._ws.on('connection', this._onConnect.bind(this));

        let jsFiles = FileUtils.readFile(this._path, "js");
        for (var f of jsFiles) {
            // logUtil.info(`process server: ${f}...`);
            // 导入js文件:
            let mapping = require(join(this._path, f));
            for (var key in mapping) {
                if (ClsUtils.targetIsCls(mapping[key], WsBaseService)) {
                    this._serverHash[key] = mapping[key]
                }
            }
        }
    }


    protected _socketVerify(info) {
        if(this.verifyFunc &&!this.verifyFunc(info))return false;
        var key = info.req.headers["sec-websocket-protocol"];
        if (!key) {
            key = createkey();
        } else if (!this.getClientByKey(key)) {
            return false;
        }
        info.req.socket.key = key;
        // console.log(info.origin);  
        // var origin = info.origin.match(/^(:?.+\:\/\/)([^\/]+)/);  
        //if (origin.length >= 3 && origin[2] == "blog.luojia.me") {  
        //    return true; //如果是来自blog.luojia.me的连接，就接受  
        //}  
        // console.log("连接",origin[2]);  
        return true; //否则拒绝  
    }

    public getClient(link: string): SocketClient {
        return this._clientHash[link];
    }

    public getClientByKey(key: string): SocketClient {
        if (this._keyHash[key] && this._clientHash[this._keyHash[key]]) {
            return this._clientHash[this._keyHash[key]];
        }
        return null;
    }

    public closeClient(linkId: string) {
        var client = this.getClient(linkId);
        if (client) {
            client.close();
        }
    }

    public send(linkId: string, data: any) {
        var client = this.getClient(linkId);
        if (client) {
            client.send(data);
        }
    }

    public sendCmd(linkId: string, cmd: string, data: any, id: number = 0) {
        var client = this.getClient(linkId);
        if (client) {
            var msg = this._protocol.encode(cmd, data, id);
            client.send(msg);
        }
    }

    private _onConnect(ws, req) {
        var socket: Socket = ws._socket;
        var key = socket["key"];
        var socketClient: SocketClient = this.getClientByKey(key);
        var ip = HttpUtils.getIp(req,this._isProxy);
        var port = socket.remotePort;
        if (socketClient) {
            socketClient.setTo(ws, ip, port);
            console.log(socketClient.id + "重连了");
            return;
        }
        // if (socketClient) {
        //     socketClient.close();
        // }
        socketClient = new SocketClient(ws, key, ip, port);
        global.log.debug("新登录id:" + socketClient.id + "-----" + key + "---" + ip + ":" + port);
        this._clientHash[socketClient.id] = socketClient;
        this._keyHash[key] = socketClient.id;
        socketClient.on('message', this._onMessage.bind(this));
        socketClient.on('close', this._onClose.bind(this));
        socketClient.on('error', this._onError.bind(this));
        this.emit("connect", socketClient);
    }

    protected async _onMessage(link: string, msg: any, client: SocketClient) {
        var msgData: IProtocolData;
        try {
            msgData = this._protocol.decode(msg);
        } catch (e) {
            global.log.error(client.id + ":" + msg);
            return;
        }
        //心跳直接过滤掉
        if (msgData == null) return;
        var cmd = msgData.cmd;
        var id = msgData.id;
        var data = msgData.data;
        if (cmd) {
            var cmdArr = cmd.split(".");
            var serverName = cmdArr[0];
            var func = cmdArr[1];
            var serverCls: any = this._serverHash[serverName];
            if (serverCls && serverCls.prototype[func]) {
                var serverCmd: WsBaseService = new serverCls(link,this);
                await serverCmd.execute(func, cmd, data, id, client);
            }
        }
        this.emit("message", link, msgData);
    }

    protected _onClose(link) {
        delete this._clientHash[link];
        for (var key in this._keyHash) {
            var id = this._keyHash[key];
            if (id == link) {
                delete this._keyHash[key];
                break;
            }
        }
        this.emit("closeClient", link);
        global.log.debug("断开了--" + link);
    }

    protected _onError(data) {
        global.log.error("socket出错了--" + data);
    }
}